/*
 ------------------------------------------------------------------------------
 Copyright (C) 2009-2011 Eternal Games.

 This file is part of the Eternal Tech source code.

 The Eternal Tech source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Eternal Tech source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Eternal Tech source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// r_local.h - Local header file to all renderer files
//


#if !defined(__R_LOCAL_H__) || !INCLUDE_GUARDS
#define __R_LOCAL_H__


#include "../ref_gl/gl_local.h"
#include "../win32/win_qgl.h"


/*
 ==============================================================================

    R_TEXTURE.CPP

 ==============================================================================
*/

#define TEXTURES_HASH_SIZE				2048

#define MAX_TEXTURES					8192

typedef short textureFlags_t;
enum {
	TF_INTERNAL				= BIT(0),
	TF_NOPICMIP				= BIT(1),
	TF_UNCOMPRESSED			= BIT(2),
	TF_INTENSITY			= BIT(3),
	TF_ALPHA				= BIT(4),
	TF_NORMALMAP			= BIT(5),
};

enum textureFilter_t {
	TF_DEFAULT,
	TF_NEAREST,
	TF_LINEAR
};

enum textureWrap_t {
	TW_REPEAT,
	TW_CLAMP,
	TW_CLAMP_TO_ZERO,
	TW_CLAMP_TO_ZERO_ALPHA
};

struct texture_t {
	char					name[MAX_PATH_LENGTH];

	int						flags;
	textureFilter_t			filter;
	textureWrap_t			wrap;

	bool					isCubeMap;

	int						frameCount;

	int						sourceWidth;
	int						sourceHeight;
	int						sourceSamples;

	int						uploadWidth;
	int						uploadHeight;
	int						uploadSize;
	uint					uploadFormat;
	uint					uploadTarget;
	uint					texNum;

	texture_t				*nextHash;
};

texture_t			*R_FindTexture (const char *name, textureFlags_t flags, textureFilter_t filter, textureWrap_t wrap);
texture_t			*R_FindCubeMapTexture (const char *name, textureFlags_t flags, textureFilter_t filter, textureWrap_t wrap, bool cameraSpace);

void				R_UpdateTextureParameters ();

bool				R_CaptureRenderToTexture (const char *name);
bool				R_UpdateTexture (const char *name, const byte *image, int width, int height);

void				R_Screenshot_f ();
void				R_EnvShot_f ();
void				R_ListTextures_f ();

void				R_InitTextures ();
void				R_ShutdownTextures ();

/*
 ==============================================================================

    R_SHADER.CPP

 ==============================================================================
*/

#define SHADERS_HASH_SIZE				512
#define MAX_SHADERS						64

#define PROGRAMS_HASH_SIZE				512
#define MAX_PROGRAMS					64

#define MAX_PROGRAM_UNIFORMS			64

#define MAX_UNIFORM_NAME_LENGTH			64

enum uniformType_t {
	UT_VIEW_ORIGIN,
	UT_VIEW_AXIS,
	UT_ENTITY_ORIGIN,
	UT_ENTITY_AXIS,
	UT_COORD_SCALE_AND_BIAS,
	UT_COLOR_SCALE_AND_BIAS,
	UT_CUSTOM
};

struct shader_t {
	char					name[MAX_PATH_LENGTH];

	bool					uploadSuccessful;
	uint					uploadTarget;

	uint					shaderId;

	int						compileStatus;

	shader_t				*nextHash;
};

struct uniform_t {
	char					name[MAX_UNIFORM_NAME_LENGTH];

	uniformType_t			type;
	int						size;
	uint					format;
	int						location;

	int						unit;

	float					values[4];
	bool					matrixIdentity;
};

struct program_t {
	char					name[MAX_PATH_LENGTH];

	shader_t				*vertexShader;
	shader_t				*fragmentShader;

	uint					programId;
	int						linkStatus;

	int						numUniforms;
	uniform_t				*uniforms;

	program_t				*nextHash;
};

shader_t			*R_FindShader (const char *name, uint type);
shader_t			*R_RegisterShader (const char *name, uint type);

uniform_t			*R_GetProgramUniform (program_t *program, const char *name);

void				R_SetProgramSampler (program_t *program, uniform_t *uniform, int unit);

void				R_UniformFloat (uniform_t *uniform, float v0);
void				R_UniformFloat2 (uniform_t *uniform, float v0, float v1);
void				R_UniformFloat3 (uniform_t *uniform, float v0, float v1, float v2);
void				R_UniformFloat4 (uniform_t *uniform, float v0, float v1, float v2, float v3);

void				R_UniformVector3 (uniform_t *uniform, const vec3_t v);

void				R_UniformMatrix3 (uniform_t *uniform, bool transpose, const mat3_t m);

program_t			*R_FindProgram (const char *name, shader_t *vertexShader, shader_t *fragmentShader);

void				R_ListShaders_f ();
void				R_ListPrograms_f ();

void				R_InitShaders ();
void				R_ShutdownShaders ();

/*
 ==============================================================================

    R_MATERIAL.CPP

 ==============================================================================
*/

#define TABLES_HASH_SIZE				1024

#define MAX_TABLES						4096
#define MAX_TABLE_SIZE					256

#define MATERIALS_HASH_SIZE				1024

#define MAX_MATERIALS					4096
#define MAX_STAGES						256

#define MAX_EXPRESSION_OPS				4096
#define MAX_EXPRESSION_REGISTERS		4096

#define MAX_SHADER_PARMS				16
#define MAX_SHADER_MAPS					8

#define MAX_TEXTURE_TRANSFORMS			4

struct table_t {
	char					name[MAX_PATH_LENGTH];
	int						index;

	bool					clamp;
	bool					snap;

	int						size;
	float					*values;

	table_t					*nextHash;
};

enum opType_t {
	OP_TYPE_MULTIPLY,
	OP_TYPE_DIVIDE,
	OP_TYPE_MOD,
	OP_TYPE_ADD,
	OP_TYPE_SUBTRACT,
	OP_TYPE_GREATER,
	OP_TYPE_LESS,
	OP_TYPE_GEQUAL,
	OP_TYPE_LEQUAL,
	OP_TYPE_EQUAL,
	OP_TYPE_NOTEQUAL,
	OP_TYPE_AND,
	OP_TYPE_OR,
	OP_TYPE_TABLE
};

enum expRegister_t {
	EXP_REGISTER_ONE,
	EXP_REGISTER_ZERO,
	EXP_REGISTER_TIME,
	EXP_REGISTER_PARM0,
	EXP_REGISTER_PARM1,
	EXP_REGISTER_PARM2,
	EXP_REGISTER_PARM3,
	EXP_REGISTER_PARM4,
	EXP_REGISTER_PARM5,
	EXP_REGISTER_PARM6,
	EXP_REGISTER_PARM7,
	EXP_REGISTER_GLOBAL0,
	EXP_REGISTER_GLOBAL1,
	EXP_REGISTER_GLOBAL2,
	EXP_REGISTER_GLOBAL3,
	EXP_REGISTER_GLOBAL4,
	EXP_REGISTER_GLOBAL5,
	EXP_REGISTER_GLOBAL6,
	EXP_REGISTER_GLOBAL7,
	EXP_REGISTER_NUM_PREDEFINED
};

typedef char materialType_t;
enum {
	MT_UNPARSED = -1,
	MT_GENERIC,
	MT_LIGHT,
	MT_NOMIP
};

enum materialCoverage_t {
	MC_OPAQUE,
	MC_PERFORATED,
	MC_TRANSLUCENT
};

typedef byte surfaceParm_t;
enum {
	SURFACEPARM_LIGHTING	= BIT(0),
	SURFACEPARM_SKY			= BIT(1),
	SURFACEPARM_WARP		= BIT(2),
	SURFACEPARM_TRANS33		= BIT(3),
	SURFACEPARM_TRANS66		= BIT(4),
	SURFACEPARM_FLOWING		= BIT(5)
};

enum subview_t {
	SUBVIEW_NONE,
	SUBVIEW_MIRROR,
	SUBVIEW_REMOTE
};

typedef short sort_t;
enum {
	SORT_BAD,
	SORT_SUBVIEW,
	SORT_OPAQUE,
	SORT_SKY,
	SORT_DECAL,
	SORT_SEE_THROUGH,
	SORT_BANNER,
	SORT_UNDERWATER,
	SORT_WATER,
	SORT_FARTHEST,
	SORT_FAR,
	SORT_MEDIUM,
	SORT_CLOSE,
	SORT_ADDITIVE,
	SORT_ALMOST_NEAREST,
	SORT_NEAREST,
	SORT_POST_PROCESS
};

enum cullType_t {
	CT_FRONT_SIDED,
	CT_BACK_SIDED,
	CT_TWO_SIDED
};

enum deform_t {
	DFRM_NONE,
	DFRM_EXPAND,
	DFRM_MOVE,
	DFRM_SPRITE,
	DFRM_TUBE
};

enum stageLighting_t {
	SL_AMBIENT,
	SL_BUMP,
	SL_DIFFUSE,
	SL_SPECULAR
};

enum texGen_t {
	TG_EXPLICIT,
	TG_VECTOR,
	TG_REFLECT,
	TG_NORMAL,
	TG_SKYBOX,
	TG_SCREEN
};

enum texTransform_t {
	TT_TRANSLATE,
	TT_SCROLL,
	TT_SCALE,
	TT_CENTERSCALE,
	TT_SHEAR,
	TT_ROTATE
};

enum vertexColor_t {
	VC_IGNORE,
	VC_MODULATE,
	VC_INVERSE_MODULATE
};

struct expOp_t {
	opType_t				opType;
	int						a;
	int						b;
	int						c;
};

struct decalInfo_t {
	float					stayTime;
	float					fadeTime;

	vec4_t					startRGBA;
	vec4_t					endRGBA;
};

struct shaderParm_t {
	uniform_t				*uniform;

	int						registers[4];
};

struct shaderMap_t {
	uniform_t				*uniform;

	texture_t				*texture;
};

struct textureStage_t {
	int						flags;
	textureFilter_t			filter;
	textureWrap_t			wrap;

	texture_t				*texture;

	texGen_t				texGen;
	vec4_t					texGenVectors[2];

	texTransform_t			texTransform[MAX_TEXTURE_TRANSFORMS];
	int						texTransformRegisters[MAX_TEXTURE_TRANSFORMS][2];
	int						numTexTransforms;
};

struct colorStage_t {
	vertexColor_t			vertexColor;

	bool					identity;

	float					scale;
	float					bias;

	int						registers[4];
};

struct shaderStage_t {
	program_t				*program;

	shader_t				*vertexShader;
	shader_t				*fragmentShader;

	float					colorScale;
	float					colorBias;

	int						numShaderParms;
	shaderParm_t			shaderParms[MAX_SHADER_PARMS];

	int						numShaderMaps;
	shaderMap_t				shaderMaps[MAX_SHADER_MAPS];
};
struct stage_t {
	int						conditionRegister;

	stageLighting_t			lighting;

	textureStage_t			textureStage;
	colorStage_t			colorStage;
	shaderStage_t			shaderStage;

	bool					shaders;

	float					specularPower;
	float					specularScale;

	bool					shadowDraw;

	bool					privatePolygonOffset;

	bool					alphaTest;
	int						alphaTestRegister;

	bool					ignoreAlphaTest;

	uint					blendSrc;
	uint					blendDst;
	bool					blend;

	bool					maskRed;
	bool					maskGreen;
	bool					maskBlue;
	bool					maskAlpha;
};

struct material_t {
	char					name[MAX_PATH_LENGTH];
	int						index;
	bool					defaulted;

	materialType_t			type;
	materialCoverage_t		coverage;

	surfaceParm_t			surfaceParm;

	int						conditionRegister;

	bool					noOverlays;
	bool					noFog;
	bool					noShadows;
	bool					noSelfShadow;

	bool					fogLight;
	bool					blendLight;
	bool					ambientLight;

	int						spectrum;

	texture_t				*lightFalloffImage;

	decalInfo_t				decalInfo;

	subview_t				subview;
	int						subviewWidth;
	int						subviewHeight;

	sort_t					sort;

	cullType_t				cullType;

	bool					polygonOffset;

	deform_t				deform;
	int						deformRegisters[3];

	stage_t					*stages;
	int						numStages;
	int						numAmbientStages;

	bool					constantExpressions;

	expOp_t					*ops;
	int						numOps;

	float					*expressionRegisters;
	int						numRegisters;

	struct mtrScript_t		*mtrScript;

	material_t				*nextHash;
};

material_t			*R_FindMaterial (const char *name, materialType_t type, surfaceParm_t surfaceParm);

void				R_EvaluateRegisters (material_t *material, float time, const float *entityParms, const float *globalParms);

void				R_ListTables_f ();
void				R_ListMaterials_f ();

void				R_InitMaterials ();
void				R_ShutdownMaterials ();

/*
 ==============================================================================

    R_FONT.CPP

 ==============================================================================
*/

#define FONTS_HASH_SIZE					512

#define MAX_FONTS						16

struct font_t {
	char					name[MAX_PATH_LENGTH];
	bool					defaulted;

	fontSet_t				fontSet;

	struct font_t			*nextHash;
};

font_t				*R_FindFont (const char *name);

void				R_ListFonts_f ();

void				R_InitFonts ();
void				R_ShutdownFonts ();

/*
 ==============================================================================

    R_MODEL.CPP

 ==============================================================================
*/

#define MODELS_HASH_SIZE				512

#define MAX_MODELS						2048

#define	SURF_PLANEBACK					0x01
#define SURF_IN_WATER					0x02
#define SURF_IN_SLIME					0x04
#define SURF_IN_LAVA					0x08

struct texInfo_t {
	int						flags;
	vec4_t					vecs[2];

	material_t				*material;
	int						width;
	int						height;
	bool					clamp;

	int						numFrames;
	texInfo_t				*next;		// Animation chain
};

struct surfTriangle_t {
	index_t					index[3];
	int						neighbor[3];
};

struct surfFacePlane_t {
	vec3_t					normal;
	float					dist;
};

struct surfVertex_t {
	vec3_t					xyz;
	vec3_t					normal;
	vec3_t					tangents[2];
	vec2_t					st;
	color_t					color;
};

struct surface_t {
	int						flags;

	int						firstEdge;	// Look up in model->edges[]. Negative
	int						numEdges;	// numbers are backwards edges

	cplane_t				*plane;

	vec3_t					origin;
	vec3_t					mins;
	vec3_t					maxs;

	texInfo_t				*texInfo;

	int						numTriangles;
	surfTriangle_t			*triangles;

	int						numVertices;
	surfVertex_t			*vertices;

	int						viewCount;
	int						worldCount;
	int						lightCount;
	int						fragmentCount;
};

struct node_t {
	// Common with leaf
	int						contents;		// -1, to differentiate from leafs
	int						viewCount;		// Node needs to be traversed if current
	int						visCount;		// Node needs to be traversed if current

	vec3_t					mins;			// For bounding box culling
	vec3_t					maxs;			// For bounding box culling

	node_t					*parent;

	// Node specific
	cplane_t				*plane;
	node_t					*children[2];	

	ushort					firstSurface;
	ushort					numSurfaces;
};

struct leaf_t {
	// Common with node
	int						contents;		// Will be a negative contents number
	int						viewCount;		// Node needs to be traversed if current
	int						visCount;		// Node needs to be traversed if current

	vec3_t					mins;			// For bounding box culling
	vec3_t					maxs;			// For bounding box culling

	node_t					*parent;

	// Leaf specific
	int						cluster;
	int						area;

	surface_t				**firstMarkSurface;
	int						numMarkSurfaces;
};

struct vis_t {
	int						numClusters;
	int						bitOfs[8][2];
};

struct vertex_t {
	vec3_t					point;
};

struct edge_t {
	ushort					v[2];
};

struct inlineModel_t {
	vec3_t					origin;			// For sounds or lights
	vec3_t					mins;
	vec3_t					maxs;
	float					radius;

	int						firstFace;
	int						numFaces;
};

struct sky_t {
	material_t				*material;

	float					rotate;
	vec3_t					axis;
};

struct mdlTriangle_t {
	index_t					index[3];
	int						neighbor[3];
};

struct mdlFacePlane_t {
	vec3_t					normal;
	float					dist;
};

struct mdlXyzNormal_t {
	vec3_t					xyz;
	vec3_t					normal;
	vec3_t					tangents[2];
};

struct mdlSt_t {
	vec2_t					st;
};

struct mdlMaterial_t {
	material_t				*material;
};

typedef struct {
	vec3_t					mins;
	vec3_t					maxs;
	float					radius;
} mdlFrame_t;

struct mdlSurface_t {
	int						numTriangles;
	int						numVertices;
	int						numMaterials;

	mdlTriangle_t			*triangles;
	mdlFacePlane_t			*facePlanes;
	mdlXyzNormal_t			*xyzNormals;
	mdlSt_t					*st;
	mdlMaterial_t			*materials;
};

struct mdl_t
{
	int						numFrames;
	int						numTags;
	int						numSurfaces;

	mdlFrame_t				*frames;
	mdlSurface_t			*surfaces;
};

enum modelType_t {
	MODEL_BAD,
	MODEL_INLINE,
	MODEL_MD2
};

struct model_t {
	char					name[MAX_PATH_LENGTH];
	char					realName[MAX_PATH_LENGTH];
	int						size;
	modelType_t				type;

	model_t					*nextHash;

	// BSP model
	sky_t					*sky;

	int						numVertices;
	vertex_t				*vertices;

	int						numEdges;
	edge_t					*edges;

	int						numSurfEdges;
	int						*surfEdges;

	int						numPlanes;
	cplane_t				*planes;

	int						numTexInfo;
	texInfo_t				*texInfo;

	int						numSurfaces;
	surface_t				*surfaces;

	int						numMarkSurfaces;
	surface_t				**markSurfaces;

	vis_t					*vis;

	int						numLeafs;
	leaf_t					*leafs;

	int						numNodes;
	node_t					*nodes;

	int						numInlineModels;
	inlineModel_t			*inlineModels;

	int						firstModelSurface;
	int						numModelSurfaces;

	vec3_t					mins;
	vec3_t					maxs;
	float					radius;

	// MD2 model
	mdl_t					*alias;
};

void		R_AddMD2Model (renderEntity_t *entity);

void		R_ListModels_f ();

void		R_InitModels ();
void		R_ShutdownModels ();

/*
 ==============================================================================

    R_MESH.CPP

 ==============================================================================
*/

#define MAX_MESHES						65536
#define MAX_POST_PROCESS_MESHES			4096

typedef void				meshData_t;

typedef short meshType_t;
enum {
	MESH_SURFACE,
	MESH_ALIASMODEL,
	MESH_SPRITE,
	MESH_BEAM,
	MESH_DECAL,
	MESH_POLY,
	MESH_NULL
};

struct mesh_t {
	uint					sort;
	meshData_t				*data;
};

void				R_SortMeshes ();

void				R_AddMeshToList (meshType_t type, meshData_t *data, material_t *material, renderEntity_t *entity);
void				R_ClearMeshLists ();

void				R_DecomposeSort (uint sort, material_t **material, renderEntity_t **entity, meshType_t *type, bool *caps);

void				R_AddSprite (renderEntity_t *entity);
void				R_AddBeam (renderEntity_t *entity);
void				R_AddEntities ();
void				R_AddParticles ();

/*
 ==============================================================================

    R_LIGHT.CPP

 ==============================================================================
*/

#define MAX_LIGHTS						4096
#define MAX_FOG_LIGHTS					1024

#define NUM_LIGHT_FRUSTUM_PLANES		6

struct lightNode_t {
	node_t					*leaf;

	int						numLeafSurfaces;
	surface_t				**leafSurfaces;

	lightNode_t				*next;
};

struct lightCache_t {
	vec3_t					origin;

	material_t				*material;
	float					materialParms[MAX_MATERIAL_PARMS];

	vec3_t					corners[8];

	vec3_t					planeNormal;
	float					planeDist;

	mat4_t					matrix;
};

struct lightSource_t {
	bool					valid;

	int						index;

	vec3_t					origin;
	vec3_t					center;
	vec3_t					angles;
	vec3_t					radius;
	int						style;
	int						detailLevel;
	bool					parallel;
	bool					noShadows;
	material_t				*material;
	float					materialParms[MAX_MATERIAL_PARMS];

	vec3_t					axis[3];
	vec3_t					corners[8];

	bool					rotated;
	vec3_t					mins;
	vec3_t					maxs;
	cplane_t				frustum[6];

	leaf_t					*leaf;
	byte					*vis;

	lightNode_t				*lightNodes;
	bool					precached;
};

struct light_t {
	vec3_t					origin;

	material_t				*material;
	float					materialParms[MAX_MATERIAL_PARMS];

	vec3_t					corners[8];

	vec3_t					planeNormal;
	float					planeDist;

	mat4_t					matrix;

	int						scissorX;
	int						scissorY;
	int						scissorWidth;
	int						scissorHeight;

	float					depthMin;
	float					depthMax;

	bool					lightInFrustum;

	bool					castShadows;

	mesh_t					*shadows[2];
	int						numShadows[2];

	mesh_t					*interactions[2];
	int						numInteractions[2];
};

void				R_LoadLights ();

void				R_AddLights ();
void				R_ClearLightMeshLists ();

void				R_AddEditorLights ();

void				R_DrawEditorLights ();

void				R_InitLightEditor ();
void				R_ShutdownLightEditor ();

/*
 ==============================================================================

    R_GENERATORS.CPP (TODO!!!)

 ==============================================================================
*/

struct generatorList_t
{
	struct generator_t *list;
	int count;
	bool inEditorMode;
	struct generator_t *selected;
};

extern generatorList_t		generators;

void				R_InitGeneratorEditor();
void				R_ShutdownGeneratorEditor();

void				R_Generators_Draw();

/*
 ==============================================================================

    R_NAVMESH.CPP (TODO!!!)

 ==============================================================================
*/

extern cvar_t *editNodes;

void Navigation_Draw();

void R_InitNavigationEditor ();
void R_ShutdownNavigationEditor ();

/*
 ==============================================================================

    R_FRONTEND.CPP

 ==============================================================================
*/

void				R_AdjustHorzCoords (horzAdjust_t adjust, float percent, float xIn, float wIn, float *xOut, float *wOut);
void				R_AdjustVertCoords (vertAdjust_t adjust, float percent, float yIn, float hIn, float *yOut, float *hOut);
void				R_AdjustHorzCoordsInt (horzAdjust_t adjust, float percent, int xIn, int wIn, int *xOut, int *wOut);
void				R_AdjustVertCoordsInt (vertAdjust_t adjust, float percent, int yIn, int hIn, int *yOut, int *hOut);

void				R_RenderView ();

/*
 ==============================================================================

    R_SCENE.CPP

 ==============================================================================
*/

void				R_ClearSceneLists ();

void				R_InitScene ();
void				R_ShutdownScene ();

/*
 ==============================================================================

    R_WORLD.CPP

 ==============================================================================
*/

void				R_AddInlineModel (renderEntity_t *entity);

leaf_t				*R_PointInLeaf (const vec3_t point);
void				R_ClusterPVS (int cluster, byte *vis);

void				R_AddWorld ();

/*
 ==============================================================================

    R_CULL.CPP

 ==============================================================================
*/

int					R_LightCullBox (lightSource_t *light, vec3_t mins, vec3_t maxs, int clipFlags);
int 				R_LightCullSphere (lightSource_t *light, const vec3_t center, float radius, int clipFlags);
int 				R_LightCullEntityBox (lightSource_t *light, renderEntity_t *entity, const vec3_t mins, const vec3_t maxs, int clipFlags);
int					R_LightCullEntitySphere (lightSource_t *light, renderEntity_t *entity, float radius, int clipFlags);

int					R_CullLightBox (const vec3_t mins, const vec3_t maxs, int clipFlags);
int					R_CullLightVolumeBox (const vec3_t corners[8], int planeBits);

int					R_CullEntityBox (renderEntity_t *entity, const vec3_t mins, const vec3_t maxs, int clipFlags);
int				    R_CullEntitySphere (renderEntity_t *entity, const vec3_t center, float radius, int clipFlags);

bool				R_CullLightSurface (surface_t *surface, renderEntity_t *entity, lightSource_t *lightSource, const vec3_t viewOrigin, int clipFlags);
bool				R_CullSurface (surface_t *surface, renderEntity_t *entity, const vec3_t viewOrigin, int clipFlags);

int					R_CullBox (vec3_t mins, vec3_t maxs, int clipFlags);
int					R_CullSphere (const vec3_t center, float radius, int clipFlags);

/*
 ==============================================================================

    R_ALIAS.CPP

 ==============================================================================
*/

void				R_AddAliasModel (renderEntity_t *entity);

/*
 ==============================================================================

    R_GLSTATE.CPP

 ==============================================================================
*/

#define MAX_TEXTURE_UNITS				8

struct glState_t {
	uint					activeUnit;
	uint					activeTarget[MAX_TEXTURE_UNITS];

	uint					texNum[MAX_TEXTURE_UNITS];
	int						texEnv[MAX_TEXTURE_UNITS];
	int						texGenS[MAX_TEXTURE_UNITS];
	int						texGenT[MAX_TEXTURE_UNITS];
	int						texGenR[MAX_TEXTURE_UNITS];
	int						texGenQ[MAX_TEXTURE_UNITS];

	uint					programId;

	mat4_t					projectionMatrix;
	mat4_t					modelviewMatrix;
	mat4_t					textureMatrix[MAX_TEXTURE_UNITS];

	bool					cullFace;
	bool					polygonOffsetFill;
	bool					alphaTest;
	bool					blend;
	bool					depthTest;
	bool					stencilTest;
	bool					textureGenS[MAX_TEXTURE_UNITS];
	bool					textureGenT[MAX_TEXTURE_UNITS];
	bool					textureGenR[MAX_TEXTURE_UNITS];
	bool					textureGenQ[MAX_TEXTURE_UNITS];
	bool					vertexShader;
	bool					fragmentShader;

	uint					cullMode;
	float					offsetFactor;
	float					offsetUnits;
	uint					alphaFunc;
	float					alphaRef;
	uint					blendSrc;
	uint					blendDst;
	uint					depthFunc;
	uint					stencilFunc;
	int						stencilRef;
	uint					stencilRefMask;
	uint					stencilFail;
	uint					stencilZFail;
	uint					stencilZPass;

	bool					colorMask[4];
	bool					depthMask;
	uint					stencilMask;

	float					depthMin;
	float					depthMax;

	uint					frontFace;

	int						scissorX;
	int						scissorY;
	int						scissorWidth;
	int						scissorHeight;

	float					depthBoundsMin;
	float					depthBoundsMax;
};

void				GL_SelectTexture (uint unit);
void				GL_EnableTexture (uint target);
void				GL_DisableTexture (void);
void				GL_BindTexture (texture_t *texture);
void				GL_TexEnv (int texEnv);
void				GL_TexGen (uint texCoord, int texGen);
void				GL_BindProgram (program_t *program);
void				GL_UnbindPrograms ();
void				GL_BindProgramTexture (uint unit, texture_t *texture);
void				GL_LoadIdentity (uint mode);
void				GL_LoadMatrix (uint mode, const float *m);
void				GL_Enable (uint cap);
void				GL_Disable (uint cap);
void				GL_CullFace (uint mode);
void				GL_PolygonOffset (float factor, float units);
void				GL_AlphaFunc (uint func, float ref);
void				GL_BlendFunc (uint src, uint dst);
void				GL_DepthFunc (uint func);
void				GL_StencilFunc (uint func, int ref, uint mask);
void				GL_StencilOp (uint fail, uint zFail, uint zPass);
void				GL_ColorMask (bool red, bool green, bool blue, bool alpha);
void				GL_DepthMask (bool mask);
void				GL_StencilMask (uint mask);
void				GL_DepthRange (float min, float max);
void				GL_FrontFace (uint face);
void				GL_Scissor (int x, int y, int width, int height);
void				GL_DepthBounds (float min, float max);

void				GL_Setup2DView ();
void				GL_Setup3DView ();

void				GL_SetDefaultState ();
void				GL_CheckForErrors ();

/*
 ==============================================================================

    R_BATCH.CPP

 ==============================================================================
*/

void				RB_CheckOverflow (int numIndices, int numVertices, int maxIndices, int maxVertices);

void				RB_SetupBatch (material_t *material, renderEntity_t *entity, bool stencilShadow, bool shadowCaps);
void				RB_RenderBatch ();

void				RB_BatchMesh (meshType_t type, meshData_t *data);
void				RB_BatchMeshShadow (meshType_t type, meshData_t *data);

/*
 ==============================================================================

    R_INTERACTION.CPP

 ==============================================================================
*/

void				RB_RenderInteraction (stage_t *bumpStage, stage_t *diffuseStage, stage_t *specularStage);

/*
 ==============================================================================

    R_RENDER.CPP

 ==============================================================================
*/

void				RB_Deform ();

void				RB_MultiplyTextureMatrix (material_t *material, textureStage_t *textureStage, mat4_t matrix);

void				RB_FillDepthBuffer (mesh_t *meshes, int numMeshes);
void				RB_RenderMaterialPasses (mesh_t *meshes, int numMeshes, qboolean postProcess);
void				RB_RenderLights (light_t *lights, int numLights);
void				RB_FogAllLights (light_t *lights, int numLights);
void				RB_RenderOverlayMaterial ();

/*
 ==============================================================================

    R_BACKEND.CPP

 ==============================================================================
*/

#define MAX_RENDER_COMMANDS				0x100000

#define MAX_INDICES						8192 * 3
#define MAX_VERTICES					4096

#define MAX_SHADOW_INDICES				MAX_INDICES * 8
#define MAX_SHADOW_VERTICES				MAX_VERTICES * 2

#define MAX_VERTEX_BUFFERS				1024

#define BUFFER_OFFSET_XYZ				0
#define BUFFER_OFFSET_NORMAL			12
#define BUFFER_OFFSET_TANGENT0			24
#define BUFFER_OFFSET_TANGENT1			36
#define BUFFER_OFFSET_ST				48
#define BUFFER_OFFSET_COLOR				56

#define BUFFER_OFFSET_XYZW				0

enum renderCommand_t {
	RC_RENDER_VIEW,
	RC_CAPTURE_RENDER,
	RC_UPDATE_TEXTURE,
	RC_STRETCH_PIC,
	RC_SHEARED_PIC,
	RC_RENDER_SIZE,
	RC_DRAW_BUFFER,
	RC_SWAP_BUFFERS,
	RC_END_OF_LIST
};

struct renderCommandList_t {
	byte					data[MAX_RENDER_COMMANDS];
	int						used;
};

struct viewport_t {
	int						x;
	int						y;
	int						width;
	int						height;
};

struct viewParms_t {
	bool					primaryView;

	subview_t				subview;

	vec3_t					origin;
	vec3_t					axis[3];

	mat4_t					perspectiveMatrix;
	mat4_t					worldMatrix;
	mat4_t					skyBoxMatrix;
	mat4_t					mirrorMatrix;
};

struct localParms_t {
	vec3_t					viewOrigin;
	mat3_t					viewAxis;
	vec3_t					lightOrigin;

	mat4_t					viewMatrix;
	mat4_t					lightMatrix;
};

struct vertexArray_t {
	vec3_t					xyz;
	vec3_t					normal;
	vec3_t					tangents[2];
	vec2_t					st;
	color_t					color;
};

struct shadowVertexArray_t {
	vec4_t					xyzw;
};

struct vertexBuffer_t
{
	char					*pointer;
	int						size;
	uint					usage;
	uint					bufNum;
};

struct renderViewCommand_t {
	int						commandId;

	float					time;
	float					materialParms[MAX_MATERIAL_PARMS];

	viewport_t				viewport;
	viewParms_t				viewParms;

	mesh_t					*meshes;
	int						numMeshes;

	mesh_t					*postProcessMeshes;
	int						numPostProcessMeshes;

	light_t					*lights;
	int						numLights;

	light_t					*fogLights;
	int						numFogLights;
};

struct captureRenderCommand_t {
	int						commandId;

	texture_t				*texture;
};

struct updateTextureCommand_t {
	int						commandId;

	texture_t				*texture;

	const byte				*image;
	int						width;
	int						height;
};

struct stretchPicCommand_t {
	int						commandId;

	float					x;
	float					y;
	float					w;
	float					h;
	float					s1;
	float					t1;
	float					s2;
	float					t2;

	color_t					color;

	material_t				*material;
};

struct shearedPicCommand_t {
	int						commandId;

	float					x;
	float					y;
	float					w;
	float					h;
	float					s1;
	float					t1;
	float					s2;
	float					t2;
	float					shearX;
	float					shearY;

	color_t					color;

	material_t				*material;
};

struct renderSizeCommand_t {
	int						commandId;

	int						width;
	int						height;
};

struct drawBufferCommand_t {
	int						commandId;

	int						width;
	int						height;
};

struct swapBuffersCommand_t {
	int						commandId;
};

struct backEndState_t {
	renderCommandList_t		commandList;

	void					(*renderBatch)();

	// General state
	bool					projection2D;
	float					time;
	float					materialParms[MAX_MATERIAL_PARMS];

	int						renderWidth;
	int						renderHeight;

	// Viewport definition
	viewport_t				viewport;

	// Render scale and bias
	vec2_t					renderScale;
	vec2_t					renderBias;

	// View parms
	viewParms_t				viewParms;

	// Local parms
	localParms_t			localParms;

	// Light state
	light_t					*light;
	material_t				*lightMaterial;
	stage_t					*lightStage;

	// Batch state
	material_t				*material;
	renderEntity_t			*entity;

	bool					stencilShadow;
	bool					shadowCaps;

	// Vertex arrays
	int						numIndices;
	int						numVertices;

	index_t					indices[MAX_INDICES];
	vertexArray_t			vertices[MAX_VERTICES];

	index_t					shadowIndices[MAX_SHADOW_INDICES];
	shadowVertexArray_t		shadowVertices[MAX_SHADOW_VERTICES];

	// Vertex buffers
	vertexBuffer_t			*vertexBuffer;
	vertexBuffer_t			*shadowVertexBuffer;
};

extern backEndState_t		backEnd;

void				RB_RenderDebugTools (const renderViewCommand_t *cmd);

void				RB_DrawElements ();
void				RB_UpdateVertexBuffer (vertexBuffer_t *vertexBuffer, const void *data, int size);

void				RB_SetLightState (renderEntity_t *entity, light_t *light, material_t *lightMaterial, stage_t *lightStage);
void				RB_SetEntityState (renderEntity_t *entity);

void				RB_ClearRenderCommands ();
void				RB_IssueRenderCommands ();
void				*RB_GetCommandBuffer (int size);

void				RB_InitBackEnd ();
void				RB_ShutdownBackEnd ();

/*
 ==============================================================================

    R_MAIN.CPP

 ==============================================================================
*/

#define MAX_MIRROR_SURFACES				1024

#define MAX_RENDER_CROPS				16

#define CULL_IN							0	// Inside the frustum
#define CULL_OUT						-1	// Outside the frustum

enum frustum_t {
	FRUSTUM_LEFT,
	FRUSTUM_RIGHT,
	FRUSTUM_TOP,
	FRUSTUM_BOTTOM,
	FRUSTUM_NEAR,
	NUM_FRUSTUM_PLANES
};

enum aspectRatio_t {
	ASPECT_NORMAL,
	ASPECT_WIDE,
	ASPECT_HIGH
};

struct viewData_t {
	mesh_t					meshes[MAX_MESHES];
	int						numMeshes;
	int						firstMesh;

	mesh_t					postProcessMeshes[MAX_POST_PROCESS_MESHES];
	int						numPostProcessMeshes;
	int						firstPostProcessMesh;

	light_t					lights[MAX_LIGHTS];
	int						numLights;
	int						firstLight;

	light_t					fogLights[MAX_FOG_LIGHTS];
	int						numFogLights;
	int						firstFogLight;
};

struct scene_t {
	renderEntity_t			entities[MAX_RENDER_ENTITIES];
	int						numEntities;
	int						firstEntity;

	renderLight_t			lights[MAX_RENDER_LIGHTS];
	int						numLights;
	int						firstLight;

	renderParticle_t		particles[MAX_RENDER_PARTICLES];
	int						numParticles;
	int						firstParticle;
};

struct lightStyle_t {
	vec3_t					rgb;
};

struct renderViewParms_t {
	bool					primaryView;

	int						viewportX;
	int						viewportY;
	int						viewportWidth;
	int						viewportHeight;

	float					fovX;
	float					fovY;
	float					fovScale;

	subview_t				subview;

	int						planeBits;

	cplane_t				frustum[NUM_FRUSTUM_PLANES];

	vec3_t					visMins;
	vec3_t					visMaxs;

	mat4_t					perspectiveMatrix;
	mat4_t					worldMatrix;
	mat4_t					skyBoxMatrix;
	mat4_t					mirrorMatrix;

	// Mesh lists
	mesh_t					*meshes;
	int						numMeshes;

	mesh_t					*postProcessMeshes;
	int						numPostProcessMeshes;

	// Light lists
	light_t					*lights;
	int						numLights;

	light_t					*fogLights;
	int						numFogLights;

	// Scene render lists
	renderEntity_t			*renderEntities;
	int						numRenderEntities;

	renderLight_t			*renderLights;
	int						numRenderLights;

	renderParticle_t		*renderParticles;
	int						numRenderParticles;
};

struct renderSubviewParms_t {
	material_t				*material;
	renderEntity_t			*entity;

	// Mirror render specific
	surface_t				*surfaces[MAX_MIRROR_SURFACES];
	int						numSurfaces;

	vec3_t					planeOrigin;
	vec3_t					planeNormal;
	float					planeDist;

	// Remote render specific
	renderView_t			*remoteView;
};

struct renderCrop_t {
	int						width;
	int						height;

	float					xScale;
	float					yScale;

	aspectRatio_t			aspectRatio;
	float					aspectScale;
	float					aspectBias;
};

struct primaryView_t {
	renderView_t			renderView;

	int						numEntities;
	int						firstEntity;

	int						numLights;
	int						firstLight;

	int						numParticles;
	int						firstParticle;
};

struct performanceCounters_t {
	int						lightEntBoxIn;
	int 					lightEntBoxOut;
	int 					lightEntBoxClip;
	int 					lightEntSphereIn;
	int 					lightEntSphereOut;
	int 					lightEntSphereClip;

	int						lightBoxIn;
	int 					lightBoxOut;
	int 					lightBoxClip;
	int 					lightSphereIn;
	int 					lightSphereOut;
	int 					lightSphereClip;

	int						entityBoxIn;
	int 					entityBoxOut;
	int 					entityBoxClip;
	int 					entitySphereIn;
	int 					entitySphereOut;
	int 					entitySphereClip;

	int						worldBoxIn;
	int 					worldBoxOut;
	int 					worldBoxClip;
	int 					worldSphereIn;
	int 					worldSphereOut;
	int 					worldSphereClip;

	int						surfaces;
	int						leafs;

	int						entities;
	int						decals;
	int						polys;

	int						deforms;
	int						deformVertices;

	int						views;
	int						draws;
	int						indices;
	int						vertices;
	int						shadowIndices;
	int						shadowVertices;

	int						vertexBuffers;
	int						vertexBufferBytes;

	int						textures;
	int						textureBytes;

	int						captureRenders;
	int						captureRenderPixels;
	int						updateTextures;
	int						updateTexturePixels;

	int						interactions;
	int						interactionsMemory;
	int						interactionsLight;
	int						interactionsFog;

	int						shadows;
	int						shadowsMemory; // Not needed
	int						shadowsZPass;
	int						shadowsZFail;

	int						lights;
	int						staticLights;
	int						dynamicLights;

	float					overdraw;
	float					overdrawShadows;
	float					overdrawLights;

	double					timeInteractions;
	double					timeShadows; // Not needed
	double					timeLights;

	double					timeFrontEnd;
	double					timeBackEnd;
};

struct reGlobals_t {
	int						frameCount;
	int						viewCount;
	int						visCount;
	int						worldCount;
	int						lightCount;
	int						fragmentCount;

	int						viewCluster;
	int						oldViewCluster;
	int						viewCluster2;
	int						oldViewCluster2;

	// Memory pools
	memoryPool_t			*shaderMemoryPool;
	memoryPool_t			*textureMemoryPool;
	memoryPool_t			*materialMemoryPool;
	memoryPool_t			*fontMemoryPool;
	memoryPool_t			*modelMemoryPool;
	memoryPool_t			*lightMemoryPool;
	memoryPool_t			*debugMemoryPool;

	// View mesh and light lists
	viewData_t				viewData;

	// Scene render lists
	scene_t					scene;

	// Light styles
	lightStyle_t			lightStyles[MAX_LIGHTSTYLES];

	// Render view/subview parms
	renderViewParms_t		renderViewParms;
	renderSubviewParms_t	renderSubviewParms;

	// Render view
	renderView_t			renderView;

	// Render crops
	renderCrop_t			renderCrops[MAX_RENDER_CROPS];
	int						numRenderCrops;

	renderCrop_t			*currentRenderCrop;

	// Some functions need a copy of the primary view
	bool				primaryViewAvailable;
	primaryView_t			primaryView;

	// The following fields can be safely used by the back-end
	performanceCounters_t	pc;

	model_t					*worldModel;
	renderEntity_t			*worldEntity;

	// Internal created assets
	texture_t				*defaultTexture;
	texture_t				*whiteTexture;
	texture_t				*blackTexture;
	texture_t				*flatTexture;
	texture_t				*attenuationTexture;
	texture_t				*noAttenuationTexture;
	texture_t				*falloffTexture;
	texture_t				*noFalloffTexture;
	texture_t				*fogTexture;
	texture_t				*fogEnterTexture;
	texture_t				*cinematicTexture;
	texture_t				*scratchTexture;
	texture_t				*accumTexture;
	texture_t				*mirrorRenderTexture;
	texture_t				*remoteRenderTexture;
	texture_t				*currentRenderTexture;

	program_t				*ambientProgram;
	program_t				*interactionProgram;

	material_t				*defaultMaterial;
	material_t				*defaultLightMaterial;
	material_t				*noDrawMaterial;
	material_t				*waterCausticsMaterial;
	material_t				*slimeCausticsMaterial;
	material_t				*lavaCausticsMaterial;

	font_t					*defaultFont;

	// Sorted materials list
	material_t				*sortedMaterials[MAX_MATERIALS];

	byte					gammaTable[256];
};

extern reGlobals_t			rg;

extern cvar_t				*r_glDriver;
extern cvar_t				*r_mode;
extern cvar_t				*r_fullscreen;
extern cvar_t				*r_customWidth;
extern cvar_t				*r_customHeight;
extern cvar_t				*r_displayRefresh;
extern cvar_t				*r_multiSamples;
extern cvar_t				*r_swapInterval;
extern cvar_t				*r_finish;
extern cvar_t				*r_gamma;
extern cvar_t				*r_contrast;
extern cvar_t				*r_brightness;

extern cvar_t				*r_logFile;
extern cvar_t				*r_ignoreGLErrors;
extern cvar_t				*r_clear;
extern cvar_t				*r_clearColor;
extern cvar_t				*r_frontBuffer;
extern cvar_t				*r_offsetFactor;
extern cvar_t				*r_offsetUnits;
extern cvar_t				*r_shadowOffsetFactor;
extern cvar_t				*r_shadowOffsetUnits;

extern cvar_t				*r_screenFraction;
extern cvar_t				*r_subviewOnly;
extern cvar_t				*r_lockPVS;
extern cvar_t				*r_zNear;
extern cvar_t				*r_zFar;
extern cvar_t				*r_singleMaterial;
extern cvar_t				*r_singleEntity;
extern cvar_t				*r_singleLight;
extern cvar_t				*r_lightScale;
extern cvar_t				*r_shadows;

extern cvar_t				*r_roundTexturesDown;
extern cvar_t				*r_downSizeTextures;
extern cvar_t				*r_downSizeNormalTextures;
extern cvar_t				*r_maxTextureSize;
extern cvar_t				*r_maxNormalTextureSize;
extern cvar_t				*r_compressTextures;
extern cvar_t				*r_compressNormalTextures;
extern cvar_t				*r_textureFilter;
extern cvar_t				*r_textureAnisotropy;
extern cvar_t				*r_textureLODBias;

extern cvar_t				*r_showCluster;
extern cvar_t				*r_showCull;
extern cvar_t				*r_showScene;
extern cvar_t				*r_showSurfaces;
extern cvar_t				*r_showMeshes;
extern cvar_t				*r_showShadows;
extern cvar_t				*r_showInteractions;
extern cvar_t				*r_showLights;
extern cvar_t				*r_showDynamic;
extern cvar_t				*r_showDeforms;
extern cvar_t				*r_showPrimitives;
extern cvar_t				*r_showVertexBuffers;
extern cvar_t				*r_showTextureUsage;
extern cvar_t				*r_showRenderToTexture;

extern cvar_t				*r_showDepth;
extern cvar_t				*r_showOverdraw;
extern cvar_t				*r_showShadowCount;
extern cvar_t				*r_showLightCount;
extern cvar_t				*r_showLightVolumes;
extern cvar_t				*r_showLightScissors;
extern cvar_t				*r_showShadowTris;
extern cvar_t				*r_showShadowVolumes;
extern cvar_t				*r_showShadowSilhouettes;
extern cvar_t				*r_showTris;
extern cvar_t				*r_showNormals;
extern cvar_t				*r_showTextureVectors;
extern cvar_t				*r_showTangentSpace;
extern cvar_t				*r_showTextureCoords;
extern cvar_t				*r_showVertexColors;
extern cvar_t				*r_showBatchSize;
extern cvar_t				*r_showModelBounds;
extern cvar_t				*r_showColorMipLevels;

extern cvar_t				*r_skipVisibility;
extern cvar_t				*r_skipAreas;
extern cvar_t				*r_skipCulling;
extern cvar_t				*r_skipSuppress;
extern cvar_t				*r_skipLightScissors;
extern cvar_t				*r_skipDepthBounds;
extern cvar_t				*r_skipLights;
extern cvar_t				*r_skipBump;
extern cvar_t				*r_skipDiffuse;
extern cvar_t				*r_skipSpecular;
extern cvar_t				*r_skipCopyToTextures;
extern cvar_t				*r_skipDynamicTextures;

void				R_AddRenderViewCommand ();


#else
FILE_WARNING
#endif   // __R_LOCAL_H__